package mmodel

import (
	"fmt"
	"reflect"
)

var SToString = func(data interface{}) string {
	return fmt.Sprintf("%v", data)
}

type Comparator interface {
	Equal(data *interface{}) bool
}

type Pair struct {
	Key interface{} `json:"key"`
	Val interface{} `json:"val"`
}

func (domain *Pair) Equal(data *interface{}) bool {
	if reflect.TypeOf(*data).Name() == "Pair" {
		p := (*data).(Pair)
		return reflect.DeepEqual(domain.Key, p.Key)
	}
	return false
}

type listMap struct {
	dataMap map[interface{}]*Pair
	keys    []interface{}
	index   int
}

func NewListMap(cap int) *listMap {
	return &listMap{
		map[interface{}]*Pair{},
		make([]interface{}, 0, cap),
		0,
	}
}
func (domain *listMap) Put(key interface{}, val interface{}) {
	if pair := domain.dataMap[key]; pair != nil {
		pair.Val = val
		index := pair.Key.(int)
		domain.keys[index] = key
	} else {
		domain.keys = append(domain.keys, key)
		domain.dataMap[key] = &Pair{len(domain.keys) - 1, val}
	}
}
func (domain *listMap) PutNotFound(key interface{}, val interface{}) bool {
	if pair := domain.dataMap[key]; pair == nil {
		domain.keys = append(domain.keys, key)
		domain.dataMap[key] = &Pair{len(domain.keys) - 1, val}
		return true
	}
	return false
}
func (domain *listMap) PutExists(key interface{}, val interface{}) bool {
	if pair := domain.dataMap[key]; pair != nil {
		pair.Val = val
		index := pair.Key.(int)
		domain.keys[index] = key
		return true
	}
	return false
}
func (domain *listMap) Length() int {
	return len(domain.keys)
}

func (domain *listMap) Get(index int) interface{} {
	if pair := domain.dataMap[domain.keys[index]]; pair != nil {
		return pair.Val
	}
	return nil
}
func (domain *listMap) GetV(key interface{}) interface{} {
	if pair := domain.dataMap[key]; pair != nil {
		return pair.Val
	}
	return nil
}
func (domain *listMap) Set(index int, val interface{}) {
	pair := domain.dataMap[domain.keys[index]]
	pair.Val = val
}
func (domain *listMap) HasNext() bool {
	return domain.index < len(domain.keys)
}
func (domain *listMap) Next() interface{} {
	pair := domain.dataMap[domain.keys[domain.index]]
	domain.index = domain.index + 1
	return pair.Val
}
func (domain *listMap) Index() int {
	return domain.index
}
func (domain *listMap) RestIndex() {
	domain.index = 0
}

func (domain *listMap) JsonMap(toString func(object interface{}) string) (data map[string]interface{}) {
	data = map[string]interface{}{}
	for index := range domain.keys {
		oldKey := domain.keys[index]
		key := toString(oldKey)
		data[key] = (*domain.dataMap[oldKey]).Val
	}
	return data
}
func (domain *listMap) Map() (data map[interface{}]interface{}) {
	data = map[interface{}]interface{}{}
	for index := range domain.keys {
		key := domain.keys[index]
		data[key] = (*domain.dataMap[key]).Val
	}
	return data
}

type Page struct {
	Page int `json:"page" validate:"gte=0"`
	Size int `json:"size" validate:"gt=0"`
}
type Pageable struct {
	Content        interface{} `json:"content"`
	Page           int         `json:"page"`
	Size           int         `json:"size"`
	First          bool        `json:"first"`
	Last           bool        `json:"last"`
	MaxPage        int         `json:"lastPage"`
	TotalElement   int64       `json:"totalElement"`
	CurrentElement int         `json:"currentElement"`
}
